package com.douqu.game.activity.server.netty;


import com.bean.core.buffer.ByteBuffer;
import com.douqu.game.activity.GameServer;
import com.douqu.game.activity.entity.BattleServerInfo;
import com.douqu.game.core.factory.CodeFactory;
import com.douqu.game.core.factory.DataFactory;
import com.douqu.game.core.netty.NettyConnection;
import com.douqu.game.core.util.BufferUtils;
import com.douqu.game.core.util.LogUtils;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;

import java.io.IOException;


/**
 * Created by bean on 2017/3/9.
 */
public class NettyTCPServerHandler extends ChannelInboundHandlerAdapter
{
    private NettyConnection connection;

    private void close()
    {
        GameServer.getInstance().removeBattleServer(connection);
    }


    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (IdleStateEvent.class.isAssignableFrom(evt.getClass())) {
            IdleStateEvent event = (IdleStateEvent) evt;
            if (event.state() == IdleState.READER_IDLE)
            {
                LogUtils.info("Reader Timeout!" + connection);
                close();
            }
        }
    }




    /*
      * channelAction
      *
      * 当客户端主动链接服务端的链接后，这个通道就是活跃的了。也就是客户端与服务端建立了通信通道并且可以传输数据
      *
      */
    public void channelActive(ChannelHandlerContext ctx) throws Exception {

        LogUtils.info("Client Connect Success:"+ctx.channel().remoteAddress());

        connection = new NettyConnection(ctx.channel(), DataFactory.currentTime);
    }



    /*
     * channelInactive
     *
     *
     * 当客户端主动断开服务端的 链接后，这个通道就是不活跃的。也就是说客户端与服务端的关闭了通信通道并且不可以传输数据
     *
     */
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {

        LogUtils.info("Client Disconnect:" + connection.getRemoteAddress());

        close();
    }


    /**
     * @param ctx
     * @param msg
     * @throws Exception
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg)
    {
        ByteBuf byteBuf = (ByteBuf) msg;
        try{
            int code = BufferUtils.readShort(byteBuf);

            LogUtils.debug("code -> " + code + " -> data length: " + byteBuf.readableBytes());

            if(CodeFactory.GET_BATTLE_SERVER_PORT == code)
            {
                int port = GameServer.getInstance().getFreeBattleServerPort();
                LogUtils.info("TCP战斗服务器获取端口:"+ port + "  ip:" + connection.getChannel().remoteAddress());
                if(port == 0)
                {
                    LogUtils.error("没有空闲战斗服务器端口了!");
                    return;
                }
                ByteBuffer out = new ByteBuffer();
                out.writeInt(port);
                connection.sendMsg(code, out.getBytes());

                BattleServerInfo battleServerInfo = new BattleServerInfo(connection, port);
                connection.setObject(battleServerInfo);
                GameServer.getInstance().addBattleServerInfo(battleServerInfo);
            }
            else if(code == CodeFactory.START_BATTLE_TCP_SERVER)
            {
                if(connection.getObject() == null || !(connection.getObject() instanceof BattleServerInfo))
                {
                    LogUtils.error("非法数据");
                    return;
                }
                LogUtils.warn("战斗服务器已经启动:"+connection);
                BattleServerInfo serverInfo = (BattleServerInfo) connection.getObject();

                LogUtils.warn("TCP战斗服务器开启，设置运行:" + serverInfo);

                ByteBuffer out = new ByteBuffer();
                out.writeBoolean(true);
                connection.sendMsg(code, out.getBytes());

                GameServer.getInstance().sendToBattleServerLogConfig();

            }

        }catch (Exception e){
            e.printStackTrace();
        }finally {
            byteBuf.release();
        }
    }


    /*
     * channelReadComplete
     *
     * channel  通道
     * Read     读取
     * Complete 完成
     *
     * 在通道读取完成后会在这个方法里通知，对应可以做刷新操作
     * ctx.flush()
     *
     */
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
        ctx.flush();
    }

    /*
     * exceptionCaught
     *
     * exception	异常
     * Caught		抓住
     *
     * 抓住异常，当发生异常的时候，可以做一些相应的处理，比如打印日志、关闭链接
     *
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception
    {
        try{
            if(cause.getClass() != IOException.class)
            {
                cause.printStackTrace();
                close();
            }

        }catch (Exception e){
            e.printStackTrace();
        }
    }


    public NettyConnection getConnection()
    {
        return connection;
    }

}
